/*
** register DLNA services on MiniSSDPd
*/

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdarg.h>

#include <httpd.h>

#include <apr_tables.h>
#include <apr_strings.h>

#include "defs.h"
#include "ssdp.h"

static void
add_req(apr_pool_t* p, apr_array_header_t* t, char* fmt, ...)
{
	va_list linep;
	va_start(linep, fmt);
	char* line = apr_pvsprintf(p, fmt, linep);

	int l = strlen(line);
	if (l > 0) {
		if (l > 0x7f)
			APR_ARRAY_PUSH(t, char*) = apr_psprintf(p, "%c%c", (0x80 | (l >> 8)), (l & 0x7f));
		else
			APR_ARRAY_PUSH(t, char*) = apr_psprintf(p, "%c", l);
		
		APR_ARRAY_PUSH(t, char*) = line;
	}
}

static int
send_req(char* req)
{
	struct sockaddr_un addr;
	int s = socket(PF_LOCAL, SOCK_STREAM, 0);
	if(s < 0)
		return -1;
	addr.sun_family = AF_UNIX;
	strncpy(addr.sun_path, SSDPD_SOCK, sizeof(addr.sun_path));
	int st = connect(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_un));
	if(st < 0) {
		fprintf(stderr, "cannot connect to MiniSSDPd.\n");
		return st;
	}

	ssize_t l0 = strlen(req);
	ssize_t l1 = 0;
	while (l1 < l0) {
		ssize_t done = write(s, req + l1, l0 - l1);
		if (done < 0) {
			close(s);
			return -1;
		}
		l1 += done;
	}

	close(s);

	return 0;
}

int
register_ssdpd(apr_pool_t *ptemp, server_rec *s, const char* uuid)
{
	apr_sockaddr_t* sockaddr;
	char* hostname;
        if (apr_sockaddr_info_get(&sockaddr, s->server_hostname, APR_UNSPEC, s->port, 0, ptemp) == APR_SUCCESS) {
		apr_sockaddr_ip_get(&hostname, sockaddr);
	} else {
		hostname = s->server_hostname; //xxx
	}

	char* rootpath =
	    (s->port > 0)
	    ? apr_psprintf(ptemp, "http://%s:%d" MODULE_ROOT "/root.xml",
		hostname,
		s->port
		)
	    : apr_psprintf(ptemp, "http://%s" MODULE_ROOT "/root.xml",
		hostname
		);

	apr_array_header_t* t = apr_array_make(ptemp, 20, sizeof(char*));
	APR_ARRAY_PUSH(t, char*) = "\x04";
	add_req(ptemp, t, "uuid:%s", uuid);
	add_req(ptemp, t, "uuid:%s::uuid:%s", uuid, uuid);
	add_req(ptemp, t, "DLNA_SERVER");
	add_req(ptemp, t, rootpath);

	char* req = apr_array_pstrcat(ptemp, t, '\0');
	if (send_req(req) < 0)
		return -1;

	apr_array_clear(t);
	APR_ARRAY_PUSH(t, char*) = "\x04";
	add_req(ptemp, t, "upnp:rootdevice");
	add_req(ptemp, t, "uuid:%s::upnp:rootdevice", uuid);
	add_req(ptemp, t, "DLNA_SERVER");
	add_req(ptemp, t, rootpath);

	req = apr_array_pstrcat(ptemp, t, '\0');
	if (send_req(req) < 0)
		return -1;

	apr_array_clear(t);
	APR_ARRAY_PUSH(t, char*) = "\x04";
	add_req(ptemp, t, "urn:schemas-upnp-org:device:MediaServer:1");
	add_req(ptemp, t, "uuid:%s::urn:schemas-upnp-org:device:MediaServer:1", uuid);
	add_req(ptemp, t, "DLNA_SERVER");
	add_req(ptemp, t, rootpath);

	req = apr_array_pstrcat(ptemp, t, '\0');
	if (send_req(req) < 0)
		return -1;

	apr_array_clear(t);
	APR_ARRAY_PUSH(t, char*) = "\x04";
	add_req(ptemp, t, "urn:schemas-upnp-org:service:ContentDirectory:1");
	add_req(ptemp, t, "uuid:%s::urn:schemas-upnp-org:service:ContentDirectory:1", uuid);
	add_req(ptemp, t, "DLNA_SERVER");
	add_req(ptemp, t, rootpath);

	req = apr_array_pstrcat(ptemp, t, '\0');
	if (send_req(req) < 0)
		return -1;

	apr_array_clear(t);
	APR_ARRAY_PUSH(t, char*) = "\x04";
	add_req(ptemp, t, "urn:schemas-upnp-org:service:ConnectionManager:1");
	add_req(ptemp, t, "uuid:%s::urn:schemas-upnp-org:service:ConnectionManager:1", uuid);
	add_req(ptemp, t, "DLNA_SERVER");
	add_req(ptemp, t, rootpath);

	req = apr_array_pstrcat(ptemp, t, '\0');
	if (send_req(req) < 0)
		return -1;

	return 0;
}
